from decimal import Decimal

from database import db_session

from flask import session

from models import *

from sqlalchemy import exc
from sqlalchemy import or_
from sqlalchemy import func

from sqlalchemy.sql.expression import func

def listar_linea_base(nombre_fase, nombre_proyecto):
    """Devuelve una lista con todos las lineas bases de la fase
    @param nombre_fase: indica el nombre de la fase
    @param nombre_proyecto: indica el nombre del proyecto
    @return items: retorna la lista de linea base"""
    items=[]

    proyecto = db_session.query(Proyecto).filter_by\
    (nombre=nombre_proyecto).one()

    fase = db_session.query(Fase).filter_by(fk_proyecto=proyecto.id).\
    filter_by(nombre=nombre_fase).one()

    lineas_base = db_session.query(LineaBase).filter_by(\
    fk_fase=fase.id).order_by(LineaBase.nombre).all()

    for lbase in lineas_base:
        elem = dict(id=lbase.id, nombre=lbase.nombre, estado=\
        lbase.estado)

        items.append(elem)

    return items

def listar_items_crear_lineabase(nombre_fase, nombre_proyecto):
    lista_items=[]

    proyecto = db_session.query(Proyecto).filter_by\
    (nombre=nombre_proyecto).one()

    fase = db_session.query(Fase).filter_by(fk_proyecto=proyecto.id).\
    filter_by(nombre=nombre_fase).one()

    lista_tipos_item = fase.tipos_item

    for tipo_item in lista_tipos_item:
        items = db_session.query(Item).filter_by\
        (fk_tipo_item=tipo_item.id).all()
        for item in items:
            if item.estado == "APR":
                elemento = dict(id=item.id, nombre=item.nombre, \
                descripcion=item.descripcion, observacion=\
                item.observacion, estado=item.estado, version=\
                item.version, complejidad=item.complejidad, costo=\
                item.costo, tipo_item=tipo_item.nombre)

                lista_items.append(elemento)

    lista_items = sorted(lista_items, key=lambda elemento: elemento['nombre'])    
    return lista_items

def validaciones_crear_lineabase(nombre, seleccionados):
    error = None
    if nombre == "":
        error = "Debe ingresar un nombre para la linea base"
        return error

    if len(seleccionados) == 0: #No selecciono ningun item
        error = "Debe seleccionar al menos un item"
        return error

    for elemento in seleccionados:
        item = db_session.query(Item).filter_by(id=int(elemento)).one()

        relaciones = db_session.query(Relacion).filter_by(\
        fk_item_destino=item.id, estado='ACT').all()

        for relacion in relaciones:
            item_origen = db_session.query(Item).filter_by(\
            id=relacion.fk_item_origen).one()

            if item_origen.estado != "APR" and item_origen.estado != "BLO":
                error = "El item '" + item.nombre + "' no posee todos \
                sus padres y/o antecesores Aprobados"
                return error

            if item_origen.estado == "APR" and str(item_origen.id) \
            not in seleccionados:
                error = "El item '" + item.nombre + "' no posee todos \
                sus padres y/o antecesores en una linea base"
                return error

    return error

def insertar_lineabase(id_usuario, nombre_proyecto, nombre_fase, \
    nombre, seleccionados):

    usuario = db_session.query(Usuario).filter_by\
    (id_usuario=id_usuario).one()

    proyecto = db_session.query(Proyecto).filter_by\
    (nombre=nombre_proyecto).one()

    fase = db_session.query(Fase).filter_by(fk_proyecto=proyecto.id).\
    filter_by(nombre=nombre_fase).one()

    fecha_actual = datetime.now()

    try:
        lineabase = LineaBase()

        lineabase.fk_fase = fase.id
        lineabase.nombre = nombre
        lineabase.estado = "ACT"
        lineabase.fecha_creacion = fecha_actual
        lineabase.usuario_creacion = usuario.id

        db_session.add(lineabase)
        db_session.flush()

        for elemento in seleccionados:
            item = db_session.query(Item).filter_by(\
            id=int(elemento)).one()

            item.estado = "BLO"

            db_session.add(item)
            db_session.flush()

            lineabase.items.append(item)
            db_session.flush()

        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message

    return 'OK'

def buscar_lineabase(cadena, campo):
    """Realiza la busqueda de las lineas bases de acuerdo al filtro 
    seleccionado (nombre, estado) y devuelve las conincidencias encontradas
    @param cadena: indica el dato que se quiere buscar
    @param campo: indica por cual campo se va a buscar
    @return items: retorna la lista con las coincidencias"""
    nombre_proyecto = session["nombre_proyecto"]
    nombre_fase = session["nombre_fase"]

    items = []

    proyecto = db_session.query(Proyecto).filter_by\
    (nombre=nombre_proyecto).one()

    fase = db_session.query(Fase).filter_by(fk_proyecto=proyecto.id).\
    filter_by(nombre=nombre_fase).one()

    if campo == "todos":
        lineasbases = db_session.query(LineaBase).filter_by(\
        fk_fase=fase.id).filter(or_(\
        func.lower(LineaBase.nombre).contains(cadena),\
        func.lower(LineaBase.estado).contains(cadena))).all()

    if campo == "nombre":
        lineasbases = db_session.query(LineaBase).filter_by(fk_fase=\
        fase.id).filter(func.lower(LineaBase.nombre).contains(cadena))\
        .all()

    if campo == "estado":
        lineasbases = db_session.query(LineaBase).filter_by(fk_fase=\
        fase.id).filter(func.lower(LineaBase.estado).\
        contains(cadena)).all()

    for lineabase in lineasbases:
        item = dict(nombre=lineabase.nombre, estado=lineabase.estado)
        items.append(item)

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def validaciones_boton_romper_lineabase(seleccionados):
    """Valida que se seleccione una linea base, y solo una
    @param seleccionados: Lista de lineas base seleccionadas"""
    error = None
    if len(seleccionados) == 0: #No selecciono ninguna linea base
        error = "Debe seleccionar una linea base"
        return error
    if len(seleccionados) > 1: #Selecciono mas de una linea base
        error = "Debe seleccionar solamente una linea base"
        return error

    id_lineabase = int(seleccionados[0])
    linea_base = db_session.query(LineaBase).filter_by\
    (id=id_lineabase).one()

    if linea_base.estado != 'COM':
        error = "Solo pueden romperse lineas base comprometidas"
        return error

    return error

def listar_items_romper_lineabase(id_lineabase):
    """Devuelve la lista de items miembro de la linea base seleccionada
    @param id_lineabase: Id de la Linea base seleccionada"""
    lista=[]

    linea_base = db_session.query(LineaBase).filter_by\
    (id=id_lineabase).one()

    for item in linea_base.items:
        tipo = db_session.query(TipoItem).filter_by\
        (id=item.fk_tipo_item).one()

        elemento = dict(nombre=item.nombre, descripcion=\
        item.descripcion, observacion=item.observacion, estado=\
        item.estado, version=item.version, complejidad=\
        item.complejidad, costo=item.costo, tipo_item=tipo.nombre )

        lista.append(elemento)

    lista = sorted(lista, key=lambda elemento: elemento['nombre'])
    return lista

def eliminar_lineabase(id_lineabase):
    try:
        linea_base = db_session.query(LineaBase).filter_by\
        (id=id_lineabase).one()

        for item in linea_base.items:
            if item.estado == 'BLO':
                item.estado = 'APR'

                db_session.add(item)
                db_session.flush()

        linea_base.estado = 'ELI'

        db_session.add(linea_base)
        db_session.flush()

        db_session.commit()
    except exc.SQLAlchemyError, e:
        db_session.rollback()
        return e.message

    return 'OK'

def listar_item_linea_base(id_lineabase):
    """Devuelve una lista con todos los items asociados a la linea base
    @param id_lineabase: indica el nombre de la fase
    @return lista: retorna la lista de linea base"""
    lista=[]

    linea_base = db_session.query(LineaBase).filter_by\
    (id=id_lineabase).one()

    for item in linea_base.items:
        tipo = db_session.query(TipoItem).filter_by\
        (id=item.fk_tipo_item).one()

        elemento = dict(id=item.id, nombre=item.nombre, descripcion=\
        item.descripcion, observacion=item.observacion, estado=\
        item.estado, version=item.version, complejidad=\
        item.complejidad, costo=item.costo, tipo_item=tipo.nombre )

        lista.append(elemento)

    lista = sorted(lista, key=lambda elemento: elemento['nombre'])
    return lista
